#include<iostream>
#include<semaphore.h>
#include<unistd.h>
using namespace std;

#if 0
class Ticket
{
public:
    Ticket() :tickets(1000) 
    {
        sem_init(&sem,0,1);//二元信号量 资源计数器的初始值为1
    }
    ~Ticket()
    {
        sem_destroy(&sem);
    }
    bool GetTicket()
    {
        bool flag = true;
        sem_wait(&sem);//想进入临界区必须先申请信号量
        if(tickets > 0)
        {
            usleep(1);
            cout << "我是 " << pthread_self() <<" 我抢到的票是: " << tickets<<endl;
            tickets--;
        }
        else{
            flag = false;
        }
        sem_post(&sem);//释放信号量
        return flag;
    }
private:
    int tickets;
    sem_t sem;
};
void* Routinue(void* arg)
{
    Ticket* t = (Ticket*)arg;
    while(1)
    {
        if(!t->GetTicket())
            break;
    }
}
#define NUM 5
int main()
{
    Ticket* t = new Ticket();
    pthread_t tid[5];
    for(int i = 0;i<NUM;i++)
        pthread_create(&tid[i],NULL,Routinue,(void*)t);
    for(int i = 0;i<NUM;i++)
        pthread_join(tid[i],NULL);
    return 0;
}

#endif

//版本2

class Sem 
{
public:
    Sem(int number) //资源计数器的初始值
    {
        sem_init(&sem,0,number);
    }
    ~Sem()
    {
        sem_destroy(&sem);
    }
    void P()
    {
        sem_wait(&sem);
    }
    void V()
    {
        sem_post(&sem);
    }
private:
    sem_t sem;
};
int tickets = 1000;
Sem sem(1);//定义一个二元信号量
void* BuyTicket(void* arg)
{
    string name = (char*)arg;
    while(1)
    {
        sem.P();//注意在此处申请信号量
        if(tickets > 0)
        {
            usleep(1);
            tickets--;
            cout << name << " get a ticket,ticket left:" << tickets<<endl;
            sem.V();
        }
        else
        {
            //注意！！！由于进入临界区的时候申请了信号量,虽然条件不满足,但在这里要释放信号量
            sem.V();
            break;
        }
    }
    cout << " 购票结束......"<<endl;
}
int main()
{
    pthread_t t1,t2,t3,t4;
    pthread_create(&t1,NULL,BuyTicket,(void*)"thread 1");
    pthread_create(&t2,NULL,BuyTicket,(void*)"thread 2");
    pthread_create(&t3,NULL,BuyTicket,(void*)"thread 3");
    pthread_create(&t4,NULL,BuyTicket,(void*)"thread 4");

    pthread_join(t1,NULL);pthread_join(t2,NULL);
    pthread_join(t3,NULL);pthread_join(t4,NULL);
    return 0;
}
